package com.dm.cloud.service.impl;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dm.cloud.api.dto.*;
import com.dm.cloud.api.service.IFUserFileService;
import com.dm.cloud.api.vo.FUserFileTaskVo;
import com.dm.cloud.api.vo.FUserFileVo;
import com.dm.cloud.api.vo.FUserFolderVo;
import com.dm.cloud.api.vo.UploadInitVo;
import com.dm.cloud.common.CloudConstant;
import com.dm.cloud.common.R;
import com.dm.cloud.dao.FMd5FileDao;
import com.dm.cloud.dao.FUserFileDao;
import com.dm.cloud.dao.FUserFileTaskDao;
import com.dm.cloud.dao.FUserFolderDao;
import com.dm.cloud.feign.auth.AuthFeign;
import com.dm.cloud.utils.Doc2PDFUtil;
import com.dm.cloud.utils.FileConst;
import com.dm.cloud.utils.FileTypeIdentifyUtils;
import com.dm.cloud.utils.distributedlock.RedisDSLock;
import com.dm.cloud.utils.http.HttpUtils;
import com.dm.cloud.utils.minio.MinioUtils;
import com.dm.cloud.utils.sql.SqlUtils;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.dm.cloud.utils.Doc2PDFUtil.getDoc2HtmlUtilInstance;

/**

 */
@Slf4j
@Service
public class FUserFileServiceImpl extends ServiceImpl<FUserFileDao, FUserFile> implements IFUserFileService {

    @Autowired
    private AuthFeign authFeign;

    @Autowired
    private FMd5FileDao md5FileDao;

    @Autowired
    private FUserFileTaskDao userFileTaskDao;

    @Autowired
    private FUserFileDao userFileDao;

    @Autowired
    private FUserFolderDao userFolderDao;

    @Override
    public R foldTree(FUserFolderVo userFolderVo) {
        List<FUserFolderVo> result =new ArrayList<>();
        try {
            //查询当前用户下面的所有文件夹
            QueryWrapper<FUserFolder> queryWrapper = new QueryWrapper<>();
            this.getCurrentUser(e -> {
                queryWrapper.eq("user_id",e.getId());
            });
            List<FUserFolder> userFolders = userFolderDao.selectList(queryWrapper);

            searchParentTree(userFolders,userFolderVo.getId(),result);
        }catch (Exception ex){
            if(result.isEmpty()){
                result.add(new FUserFolderVo());
            }
        }
        return R.data(result);
    }

    private void searchParentTree(List<FUserFolder> allFolder,Integer currentFolderId , List<FUserFolderVo> result){
        Optional<FUserFolder> currentFolder = allFolder.stream().filter(e->e.getId().compareTo(currentFolderId) == 0).findFirst();
        if(currentFolder.isPresent()){

            FUserFolder fuf =  currentFolder.get();

            //存在该文件夹节点
            FUserFolderVo cu = new FUserFolderVo();
            cu.setId(fuf.getId());
            cu.setFolder(fuf.getFolder());
            result.add(cu);
            Integer parentFolderId = fuf.getParentFolderId();
            if(ObjectUtils.isNotNull(parentFolderId)){
                //父节点存在
                searchParentTree(allFolder,parentFolderId,result);
            }else{
                //没有父节点了 序列反转 最顶上是最顶级文件夹
                result.add(new FUserFolderVo());
                Collections.reverse(result);
            }
        }else{
            throw new RuntimeException("该文件夹不存在");
        }
    }

    @Override
    public R foldCreate(FUserFolderVo userFolderVo) {
        try {
            FUserFolder userFolder = new FUserFolder();
            QueryWrapper<FUserFolder> queryWrapper = new QueryWrapper<>();
            this.getCurrentUser(e -> {
                userFolder.setParentFolderId(userFolderVo.getParentFolderId());
                if(ObjectUtils.isNotNull(userFolderVo.getParentFolderId())) {
                    queryWrapper.eq("parent_folder_id", userFolderVo.getParentFolderId());
                }else{
                    queryWrapper.isNull("parent_folder_id");
                }
                userFolder.setUserId(e.getId());
                queryWrapper.eq("user_id",e.getId());
                userFolder.setFolder(userFolderVo.getFolder());
                queryWrapper.eq("folder",userFolderVo.getFolder());
            });
            if(userFolderDao.selectCount(queryWrapper) > 0){
                String newFolderName = userFolder.getFolder() + "_" +UUID.randomUUID().toString().replace("-","");
                userFolder.setFolder(newFolderName);
            }
            userFolderDao.insert(userFolder);
        }catch (Exception ex){
            log.error(String.format("创建文件夹【%s】失败",userFolderVo.getFolder()));
            return R.failure("文件夹创建失败");
        }
        return R.success();
    }

    @Override
    public R foldUpdate(FUserFolderVo userFolderVo) {
        try {
            FUserFolder userFolder = new FUserFolder();
            QueryWrapper<FUserFolder> queryWrapper = new QueryWrapper<>();
            this.getCurrentUser(e -> {
                userFolder.setFolder(userFolderVo.getFolder());
                userFolder.setId(userFolderVo.getId());
                queryWrapper.eq("folder",userFolderVo.getFolder());
                queryWrapper.eq("user_id",e.getId());
                queryWrapper.eq("parent_folder_id",userFolderVo.getParentFolderId());
            });
            if(userFolderDao.selectCount(queryWrapper)>0){
                return R.failure("该文件夹已存在");
            }
            userFolderDao.updateById(userFolder);
        }catch (Exception ex){
            log.error(String.format("修改文件夹【%s】【%s】失败",userFolderVo.getId(),userFolderVo.getFolder()));
            return R.failure("文件夹修改失败");
        }
        return R.success();
    }

    @Override
    @Transactional
    public R foldDelete(FUserFolderVo userFolderVo) {
        try {
            this.getCurrentUser(e -> {
                //查找该文件下的所有文件夹
                QueryWrapper<FUserFolder> q = new QueryWrapper<>();
                q.eq("user_id",e.getId());
                List<FUserFolder> list = userFolderDao.selectList(q);

                List<FUserFolder> allFolderWithChild = new ArrayList<>();
                getAllChildFolder(list,userFolderVo.getId(),allFolderWithChild);

                //包当前文件夹也包含进去
                FUserFolder userf =  new FUserFolder();
                userf.setId(userFolderVo.getId());
                allFolderWithChild.add(userf);

                //删除当前用户该文件夹下的文件列表(包含内部文件夹的文件)
                QueryWrapper<FUserFile> deletefQ = new QueryWrapper();
                deletefQ.in("folder_id",allFolderWithChild.stream().map(FUserFolder::getId).collect(Collectors.toList()));
                deletefQ.eq("user_id",e.getId());
                userFileDao.delete(deletefQ);

                //删除当前该文件夹下的文件夹和该文件(包含内部文件夹)
                QueryWrapper<FUserFolder> deleteQ = new QueryWrapper();
                deleteQ.eq("user_id",e.getId());
                deleteQ.and(
                        wap-> wap.in("parent_folder_id", allFolderWithChild.stream().map(FUserFolder::getId).collect(Collectors.toList()))
                                    .or()
                                    .eq("id", userFolderVo.getId())
                );
                userFolderDao.delete(deleteQ);
            });
        }catch (Exception ex){
            log.error(String.format("修改文件夹【%s】【%s】失败",userFolderVo.getId(),userFolderVo.getFolder()));
            throw new RuntimeException("文件夹删除失败");
        }
        return R.success();
    }

    private void getAllChildFolder(List<FUserFolder> allFolder,Integer currentFolderId , List<FUserFolder> result){
        if(ObjectUtils.isNull(currentFolderId)){
            //表示是最顶级的文件夹 包含所有文件夹
            result = allFolder;
        }else{
            List<FUserFolder> tmp1List = allFolder.stream().filter(e->ObjectUtils.isNotNull(e.getParentFolderId()) && e.getParentFolderId().compareTo(currentFolderId) == 0).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(tmp1List)){
                for (FUserFolder userFolder : tmp1List) {
                    result.add(userFolder);
                    getAllChildFolder(allFolder,userFolder.getId(),result);
                }
            }
        }
    }

    @Override
    public R getFileList(FUserFileVo condition) {

//        初始化返回结果内容
        List<FUserFileVo> result = new ArrayList<>();

        //初始化查询条件
        QueryWrapper<FUserFile> wrapper = new QueryWrapper();
        QueryWrapper<FUserFolder> folderWrapper = new QueryWrapper();

        if(StringUtils.isNotEmpty(condition.getFileName())){
            wrapper.like("file_name",condition.getFileName());
            folderWrapper.like("folder",condition.getFileName());
        }
        if(ObjectUtils.isNotNull(condition.getFileType())){
            if (-1==condition.getFileType()){
                //查找最近 七天的
                LocalDateTime dateTime = LocalDateTime.now();
                dateTime = dateTime.plusDays(-7);
                String dt = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
                wrapper.gt("upload_time", dt);
                folderWrapper.gt("create_time",dt);
            }else if(6==condition.getFileType()){
                //没分类的文件
                Map<String,Integer> fileTypes = new FileTypeIdentifyUtils().getAllTypes();
                String cur_type = fileTypes.entrySet().stream().map(e->"("+e.getKey()+")").collect(Collectors.joining( "|"));
                wrapper.apply(" and file_name REGEXP '^.*(?<!"+cur_type+")$' ");
            }else{
                Map<String,Integer> fileTypes = new FileTypeIdentifyUtils().getAllTypes();
                String cur_type = fileTypes.entrySet().stream().filter(e->e.getValue() == condition.getFileType()).map(Map.Entry::getKey).collect(Collectors.joining("|"));
                wrapper.apply(" and file_name REGEXP '^.*"+ cur_type +"$' ");
            }
        }
        //调用Auth服务
        this.getCurrentUser((user) -> {
            //响应成功 获取ID
            Integer user_id = user.getId();
            //根据ID获取上传列表
            wrapper.eq("user_id",user_id);
            folderWrapper.eq("user_id",user_id);
        });

        folderWrapper.orderByDesc("create_time");
        wrapper.orderByDesc("upload_time");

        //不按照文件类型查询
        if(ObjectUtils.isNull(condition.getFileType())) {
            //前端没有传回文件夹选项 表示展示首层文件 即没有父文件的文件和文件夹
            //有的话则传回该文件夹下的文件和文件夹
            if(ObjectUtils.isNotNull(condition.getFolderId())){
                wrapper.eq("folder_id",condition.getFolderId());
                folderWrapper.eq("parent_folder_id",condition.getFolderId());
            }else{
                wrapper.isNull("folder_id");
                folderWrapper.isNull("parent_folder_id");
            }
            //先查询文件夹列表
            List<FUserFolder> folderList = userFolderDao.selectList(folderWrapper);
            if (CollectionUtils.isNotEmpty(folderList)) {
                //文件夹下存在文件夹 整理
                for (FUserFolder fUserFolder : folderList) {
                    FUserFileVo resIn = new FUserFileVo();
                    resIn.setFileType(0);
                    resIn.setId(fUserFolder.getId());
                    resIn.setFileName(fUserFolder.getFolder());
                    resIn.setUploadTime(fUserFolder.getCreateTime());
                    result.add(resIn);
                }

            }
            //再查询文件列表
            List<FUserFile> fileList = userFileDao.selectList(wrapper);
            if (CollectionUtils.isNotEmpty(fileList)) {
                //文件夹下存在文件夹 整理
                for (FUserFile userFile : fileList) {
                    FUserFileVo resIn = new FUserFileVo();
                    //fileType 1标识文件
                    resIn.setFileType(1);
                    resIn.setId(userFile.getId());
                    resIn.setFileName(userFile.getFileName());
                    resIn.setUploadTime(userFile.getUploadTime());
                    result.add(resIn);
                }
            }
        }else{
            //查询文件列表
            List<FUserFile> fileList = userFileDao.selectList(wrapper);
            if (CollectionUtils.isNotEmpty(fileList)) {
                //文件夹下存在文件夹 整理
                for (FUserFile userFile : fileList) {
                    FUserFileVo resIn = new FUserFileVo();
                    //fileType 1标识文件
                    resIn.setFileType(1);
                    resIn.setId(userFile.getId());
                    resIn.setFileName(userFile.getFileName());
                    resIn.setUploadTime(userFile.getUploadTime());
                    result.add(resIn);
                }
            }
        }
        return R.data(result);
    }

    @Override
    public R filePublicList(FUserFileVo condition) {
        //初始化查询条件
        QueryWrapper<FUserFile> wrapper = new QueryWrapper();
        if(StringUtils.isNotBlank(condition.getFileName())){
            wrapper.like("file_name",condition.getFileName());
        }
        wrapper.eq("public_flag",FileConst.FILE_SHARE_TYPE_PUBLIC);
        IPage<FUserFile> page = new Page<>();
        page.setSize(condition.getPageSize());
        page.setCurrent(condition.getPage());

        SqlUtils.order(wrapper,condition);
        return R.data(this.page(page,wrapper));
    }

    @Override
    public R deleteFile(FUserFileVo condition) {
        //判断当前用户和当前资源是否是又关联关系的
        QueryWrapper<FUserFile> wrapper = new QueryWrapper();
        //文件ID
        if(ObjectUtils.isNotNull(condition.getId())){
            wrapper.eq("id",condition.getId());
        }

        this.getCurrentUser((user) -> {
            //响应成功 获取ID
            Integer user_id = user.getId();
            //用户ID
            wrapper.eq("user_id",user_id);
        });

        //查询文件关联关系是否存在
        if(this.baseMapper.selectCount(wrapper)>0){
            /**
             * 两种删除逻辑，
             * 1、只删除关联关系 不删除实际已存储文件
             * 2、删除关联关系之前判断该文件是不是还关联了其他人，没有的话删除文件
             * 此处取方式 1
             */
            this.baseMapper.deleteById(condition.getId());
            return R.success();
        }else{
            return R.failure("非资源所有者无权删除！");
        }
    }

    @Override
    public R updateFile(FUserFileVo condition) {
        try {
            FUserFile userFile = new FUserFile();
            QueryWrapper<FUserFile> queryWrapper = new QueryWrapper<>();
            this.getCurrentUser(e -> {
                userFile.setFileName(condition.getFileName());
                userFile.setId(condition.getId());
                queryWrapper.ne("id",condition.getId());
                queryWrapper.eq("file_name",condition.getFileName());
                queryWrapper.eq("user_id",e.getId());
                if(ObjectUtils.isNotNull(condition.getFolderId())){
                    queryWrapper.eq("folder_id",condition.getFolderId());
                }else{
                    queryWrapper.isNull("folder_id");
                }
            });
            if(userFileDao.selectCount(queryWrapper)>0){
                return R.failure("该文件名已存在");
            }
            userFileDao.updateById(userFile);
        }catch (Exception ex){
            log.error(String.format("修改文件【%s】【%s】失败",condition.getId(),condition.getFileName()));
            return R.failure("文件名修改失败");
        }
        return R.success();
    }

    @Override
    public R createTask(FUserFileTaskVo condition) {
        //先查询当前用户当前文件夹下是不是已经存在该文件 存在该文件要将当前文件改名字
        //直接进入循环 如果没有重复文件 跳出循环

        //文件夹id
        Integer folderId = condition.getFolderId();
        //文件名
        String fileName = condition.getFileName();
        //文件后缀
        String[] fileSplits = fileName.split("\\.");
        String fileSuffix = fileSplits[fileSplits.length -1];
        //文件md5
        String md5 = condition.getMd5();
        Assert.notEmpty(md5,"文件MD5信息缺失");
        //用户ID
        AtomicReference<Integer> userId = new AtomicReference<>();

        if (1 == condition.getType()){
            //获取是否存在同名文件
            this.getCurrentUser((users) -> {
                //指定用户ID
                userId.set(users.getId());
                Assert.notNull(userId.get(),"用户信息获取失败");
            });
            //获取锁 最多等待5秒
            if(RedisDSLock.tryLockForever(FileConst.UPLOAD_FILE_CREATE_TASK_LOCK_PREFIX
                    +"&"+userId.get()
                    +"&"+folderId
                    +"&"+fileName
                    +"&"+md5,folderId+fileName+md5,10000)){
                try {
                    //查询
                    String pre = fileSplits[0];
                    String suffix = Arrays.stream(fileSplits).skip(1).collect(Collectors.joining("."));
                    List<String> files = new ArrayList<>();

                    //查询文件列表该文件夹中是不是已经存在同名文件
                    QueryWrapper<FUserFile> queryWrapper2 = new QueryWrapper<>();
                    queryWrapper2.eq("user_id", userId.get());
                    if (ObjectUtils.isNotNull(folderId)) {
                        queryWrapper2.eq("folder_id", folderId);
                    } else {
                        queryWrapper2.isNull("folder_id");
                    }
                    queryWrapper2.likeRight("file_name", pre);
                    List<FUserFile> exsitFiles = userFileDao.selectList(queryWrapper2);
                    //先判断相同文件是否存在]
                    String finalFileName = fileName;
                    if(exsitFiles.stream().filter(e->md5.equals(e.getMd5()) && finalFileName.equals(e.getFileName())).count()>0 ){
                        return R.failure("当前文件夹下已存在该文件");
                    }

                    //查询任务中该文件夹下是不是有正在执行上传的同名文件
                    QueryWrapper<FUserFileTask> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("user_id", userId.get());
                    if (ObjectUtils.isNotNull(folderId)) {
                        queryWrapper.eq("folder_id", folderId);
                    } else {
                        queryWrapper.isNull("folder_id");
                    }
                    queryWrapper.likeRight("file_name", pre);
                    queryWrapper.notIn("status", FileConst.UPLOAD_FILE_STATUS_FINISHED,FileConst.UPLOAD_FILE_STATUS_STOPED);//未完成的上传任务
                    List<FUserFileTask> exsitFileTasks = userFileTaskDao.selectList(queryWrapper);
                    //先判断相同文件是否存在
                    if(exsitFileTasks.stream().filter(e->md5.equals(e.getMd5()) && finalFileName.equals(e.getFileName())).count()>0){
                        //相同任务已存在时 直接返回
                        return R.data("该文件已在上传列表中");
                    }

                    if(CollectionUtils.isNotEmpty(exsitFiles)){
                        files.addAll(exsitFiles.stream().map(FUserFile::getFileName).collect(Collectors.toList()));
                    }
                    if(CollectionUtils.isNotEmpty(exsitFileTasks)){
                        files.addAll(exsitFileTasks.stream().map(FUserFileTask::getFileName).collect(Collectors.toList()));
                    }
                    if(CollectionUtils.isNotEmpty(files)){
                        //获取文件名中的序号  这是一个文件名(1).txt
                        Optional<Integer> maxXh =  files.stream().map(e->{
                            String[] exsitSplit = e.split("\\.");
                            //从第一部分截取序号
                            String preInner = exsitSplit[0];
                            if(preInner.contains("(") && preInner.contains(")")){
                                //包含序号返回序号
                                String ss = preInner.split("\\(")[1].split("\\)")[0];
                                try{
                                    return Integer.valueOf(ss);
                                }catch (Exception ex){
                                    return 0;
                                }
                            }else{
                                //不包含序号 返回0
                                return 0;
                            }
                        }).max((x,y)->x.compareTo(y));
                        if(maxXh.isPresent()){
                            fileName = pre + "(" + (maxXh.get() + 1) + ")" + "." + suffix;
                        }
                    }

                    //创建上传任务
                    FUserFileTask userFileTask = new FUserFileTask();
                    //用户ID
                    userFileTask.setUserId(userId.get());
                    //文件夹ID
                    userFileTask.setFolderId(folderId);
                    //文件MD5
                    userFileTask.setMd5(md5);
                    //文件名
                    userFileTask.setFileName(fileName);
                    //传输类型 上传
                    userFileTask.setType(condition.getType());
                    //传输状态 等待上传
                    userFileTask.setStatus(FileConst.UPLOAD_FILE_STATUS_WAIT);

                    if(userFileTaskDao.insert(userFileTask)>0){
                        //查询出来ID
                        QueryWrapper<FUserFileTask> userFileTaskQueryWrapper = new QueryWrapper<>();
                        userFileTaskQueryWrapper.eq("user_id",userId.get());
                        if(ObjectUtils.isNotNull(folderId)) {
                            userFileTaskQueryWrapper.eq("folder_id", folderId);
                        }else{
                            userFileTaskQueryWrapper.isNull("folder_id");
                        }
                        userFileTaskQueryWrapper.eq("file_name",fileName);
                        userFileTaskQueryWrapper.eq("status",FileConst.UPLOAD_FILE_STATUS_WAIT);
                        userFileTaskQueryWrapper.eq("type",condition.getType());
                        FUserFileTask one = userFileTaskDao.selectOne(userFileTaskQueryWrapper);

                        return R.success(one.getId());
                    }else{
                        return R.failure("上传任务创建失败");
                    }
                }finally {
                    RedisDSLock.unLock(FileConst.UPLOAD_FILE_CREATE_TASK_LOCK_PREFIX
                            +"&"+userId.get()
                            +"&"+folderId
                            +"&"+fileName
                            +"&"+md5,folderId+fileName+md5);
                }
            }
        }else{
            //下载任务
            //...
        }
        return null;
    }

    @Override
    public R initMultiPartUpload(Integer partCount,String objectName,String contentType) {
        /**
         * 判断当前任务列表已经存在 则获取自己需要上传的分片链接。。。
         */
        UploadInitVo result = new UploadInitVo();
        //查询文件是否已经上传完成了
        QueryWrapper<FMd5File> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5",objectName);
        if(md5FileDao.selectCount(queryWrapper)>0){
            //上传完成了 不需要上传了 结束
            result.setFinished(true);
        }else{
            if (partCount == 1) {
                //只有一个分片的情况下 直接返回上传地址
                String uploadObjectUrl = MinioUtils.getUploadObjectUrl(MinioUtils.FILE_WAREHOUSE,objectName);
                result.setUploadUrl(new ArrayList<String>(){{add(uploadObjectUrl);}});
            }else {

                Map<String, Object> initRsl = MinioUtils.initMultiPartUpload(MinioUtils.FILE_WAREHOUSE, objectName, partCount, contentType);

                result.setFinished(false);
                result.setUploadId(initRsl.get("uploadId").toString());
                result.setUploadUrl((List<String>)initRsl.get("uploadUrls"));
            }
        }
        return R.data(result);
    }

    private void stopTask(Integer tid){
        FUserFileTask userFileTask = new FUserFileTask();
        userFileTask.setId(tid);
        userFileTask.setStatus(9);
        userFileTaskDao.updateById(userFileTask);
    }

    @Override
    public R mergeMultipartUpload(Integer tid,String md5, String uploadId,Integer chuncks, boolean finished) {
        //不是秒传的任务 先处理文件合并的操作
        if(!finished) {
            //判断分片数量  分片数量是一标识直接传完了
            if(chuncks>1) {
                //先判断文件列表是否完整
                List<String> partList = MinioUtils.getExsitParts(MinioUtils.FILE_WAREHOUSE, md5, uploadId);
                if (CollectionUtils.isNotEmpty(partList)) {
                    //上传列表不是空 判断上传列表是否完整
                    if (chuncks.compareTo(partList.size()) < 0) {
                        //缺少分片
                        stopTask(tid);
                        return R.failure("文件分片缺失，请重新上传");
                    } else {
                        //分片完整 整合并返回
                        boolean success = MinioUtils.mergeMultipartUpload(MinioUtils.FILE_WAREHOUSE, md5, uploadId);
                        if (!success) {
                            //合并失败
                            stopTask(tid);
                            return R.failure("合并文件异常");
                        }
                    }
                } else {
                    stopTask(tid);
                    return R.failure("文件分片缺失，请重新上传");
                }
            }
        }
        //对于上传完成的任务可以将任务状态修改并添加到用户文件库
        try {
            if (RedisDSLock.tryLockForever(FileConst.UPLOAD_FILE_MD5_LOCK_PREFIX
                    + "&" + md5, md5, 10000)) {
                //MD5文件列表添加
                FMd5File fMd5File = new FMd5File();
                fMd5File.setMd5(md5);
                md5FileDao.insert(fMd5File);

                //数据库中当前md5的所有上传任务尚未执行完成的
                QueryWrapper<FUserFileTask> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("md5", md5);
                queryWrapper.notIn("status", FileConst.UPLOAD_FILE_STATUS_FINISHED,FileConst.UPLOAD_FILE_STATUS_STOPED);
                queryWrapper.eq("type", 1);

                List<FUserFileTask> tasks = userFileTaskDao.selectList(queryWrapper);
                if (CollectionUtils.isNotEmpty(tasks)) {
                    // 关系添加
                    List<FUserFile> insertFiles = new ArrayList<>();
                    for (FUserFileTask task : tasks) {
                        FUserFile userFile = new FUserFile();
                        userFile.setUserId(task.getUserId());
                        userFile.setFileName(task.getFileName());
                        userFile.setFolderId(task.getFolderId());
                        userFile.setMd5(task.getMd5());
                        userFile.setUploadTime(new Date());
                        insertFiles.add(userFile);
                    }
                    //批量插入
                    userFileDao.batchInsert(insertFiles);

                    FUserFileTask updateTask = new FUserFileTask();
                    updateTask.setStatus(3);//任务修改为已完成
                    userFileTaskDao.update(updateTask, queryWrapper);
                }
            }
        }finally {
            //释放锁
            stopTask(tid);
            RedisDSLock.unLock(FileConst.UPLOAD_FILE_MD5_LOCK_PREFIX+ "&" + md5, md5);
        }
        return R.data("合并成功");
    }

    @Override
    public R getDownLoadUrl(Integer id) {
        //根据id获取文件 根据文件获取 地址
        FUserFile userFile = userFileDao.selectById(id);
        if(ObjectUtils.isNotNull(userFile)){
            //这块可以写到配置里面
            return R.data("http://localhost:9000/"+MinioUtils.FILE_WAREHOUSE+"/"+userFile.getMd5());
        }

        return R.failure("下载地址已失效");
    }

    @Override
    public R openOfficePreview(Integer id) {
        //现根据id获取文件信息
        FUserFile userFile = userFileDao.selectById(id);
        if(ObjectUtils.isNotNull(userFile)){
            //这块可以写到配置里面
            String uri = "http://localhost:9000/"+MinioUtils.FILE_WAREHOUSE+"/"+userFile.getMd5();
            String fileName = userFile.getFileName();
            String suffix = "";
            if(fileName.lastIndexOf(".")>=0){
                suffix = fileName.substring(fileName.lastIndexOf(".")+1);
            }

            InputStream fileInputStream = null;
            try {
                Response fileRes = HttpUtils.doGet(uri);
                ResponseBody body = fileRes.body();
                BufferedSource source = body.source();
                source.request(Long.MAX_VALUE);
                Buffer buffer = source.buffer();
                fileInputStream = body.byteStream();
            } catch (Exception e) {
                log.error("文件获取失败");
                return R.failure("文件获取失败");
            }

            Doc2PDFUtil coc2HtmlUtil = getDoc2HtmlUtilInstance();
            try {
                String sdsds = coc2HtmlUtil.fileToPDF(fileInputStream,suffix);
                return R.data("./files/" + sdsds);
            } catch (IOException e) {
                log.error("转换文件失败");
                return R.failure("转换文件失败");
            }
        }else{
            return R.failure("文件已失效");
        }
    }

    @Override
    public R removeMultiTask(String uploadId,String objectNme) {
        return R.data(MinioUtils.removeMultipartUpload(MinioUtils.FILE_WAREHOUSE,objectNme,uploadId));
    }

    @Override
    public R clearMultiTask(String objectName) {
        return R.data(MinioUtils.clearMultipartUpload(MinioUtils.FILE_WAREHOUSE));
    }

    @Override
    public R addLifeCycle() {
        MinioUtils.addBucketLifeCycleConfiguration(MinioUtils.FILE_WAREHOUSE);
        return R.success();
    }

    @Override
    public R deleteLifeCycle() {
        MinioUtils.removeBucketLifeCycleConfiguration(MinioUtils.FILE_WAREHOUSE);
        return R.success();
    }

    /**
     * 获取当前用户后的操作
     * @param consumer
     */
    private void getCurrentUser(Consumer<Users> consumer){
        //调用auth服务
        R<Users> user = authFeign.getCurrentUser(CloudConstant.AUTH_REQUEST_UUID);
        if("success".equals(user.getType())
                && CloudConstant.RESPONSE_SUCCESS_CODE == user.getCode()
                && Optional.ofNullable(user.getResult()).isPresent()) {
            Users userDto = user.getResult();
            if(null != consumer){
                consumer.accept(userDto);
            }
        }else{
            throw new RuntimeException("用户信息获取失败，请重新登陆尝试");
        }
    }

    /**
     * 获取未上传的最靠前分片
     * @param uploadList
     * @param all
     * @return
     */
    private Integer getMinPartUnUpload(List<Integer> uploadList,Integer all){
        List<Integer> allList = IntStream.rangeClosed(1,all).boxed().collect(Collectors.toList());
        allList.removeAll(uploadList);
        return allList.stream().sorted().collect(Collectors.toList()).get(0);
    }
}